/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxMarker =
    {
        /**
         * Class: mxMarker
         *
         * A static class that implements all markers for VML and SVG using a
         * registry. NOTE: The signatures in this class will change.
         *
         * Variable: markers
         *
         * Maps from markers names to functions to paint the markers.
         */
        markers: [],

        /**
         * Function: addMarker
         *
         * Adds a factory method that updates a given endpoint and returns a
         * function to paint the marker onto the given canvas.
         */
        addMarker: function(type, funct)
        {
            mxMarker.markers[type] = funct;
        },

        /**
         * Function: createMarker
         *
         * Returns a function to paint the given marker.
         */
        createMarker: function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
        {
            var funct = mxMarker.markers[type];

            return (funct != null) ? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) : null;
        }

    };

/**
 * Adds the classic and block marker factory method.
 */
(function()
{
    function createArrow(widthFactor)
    {
        widthFactor = (widthFactor != null) ? widthFactor : 2;

        return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
        {
            // The angle of the forward facing arrow sides against the x axis is
            // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
            // only half the strokewidth is processed ).
            var endOffsetX = unitX * sw * 1.118;
            var endOffsetY = unitY * sw * 1.118;

            unitX = unitX * (size + sw);
            unitY = unitY * (size + sw);

            var pt = pe.clone();
            pt.x -= endOffsetX;
            pt.y -= endOffsetY;

            var f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
            pe.x += -unitX * f - endOffsetX;
            pe.y += -unitY * f - endOffsetY;

            return function()
            {
                canvas.begin();
                canvas.moveTo(pt.x, pt.y);
                canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);

                if (type == mxConstants.ARROW_CLASSIC || type == mxConstants.ARROW_CLASSIC_THIN)
                {
                    canvas.lineTo(pt.x - unitX * 3 / 4, pt.y - unitY * 3 / 4);
                }

                canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
                canvas.close();

                if (filled)
                {
                    canvas.fillAndStroke();
                }
                else
                {
                    canvas.stroke();
                }
            };
        }
    };

    mxMarker.addMarker('classic', createArrow(2));
    mxMarker.addMarker('classicThin', createArrow(3));
    mxMarker.addMarker('block', createArrow(2));
    mxMarker.addMarker('blockThin', createArrow(3));

    function createOpenArrow(widthFactor)
    {
        widthFactor = (widthFactor != null) ? widthFactor : 2;

        return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
        {
            // The angle of the forward facing arrow sides against the x axis is
            // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
            // only half the strokewidth is processed ).
            var endOffsetX = unitX * sw * 1.118;
            var endOffsetY = unitY * sw * 1.118;

            unitX = unitX * (size + sw);
            unitY = unitY * (size + sw);

            var pt = pe.clone();
            pt.x -= endOffsetX;
            pt.y -= endOffsetY;

            pe.x += -endOffsetX * 2;
            pe.y += -endOffsetY * 2;

            return function()
            {
                canvas.begin();
                canvas.moveTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
                canvas.lineTo(pt.x, pt.y);
                canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
                canvas.stroke();
            };
        }
    };

    mxMarker.addMarker('open', createOpenArrow(2));
    mxMarker.addMarker('openThin', createOpenArrow(3));

    mxMarker.addMarker('oval', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
    {
        var a = size / 2;

        var pt = pe.clone();
        pe.x -= unitX * a;
        pe.y -= unitY * a;

        return function()
        {
            canvas.ellipse(pt.x - a, pt.y - a, size, size);

            if (filled)
            {
                canvas.fillAndStroke();
            }
            else
            {
                canvas.stroke();
            }
        };
    });

    function diamond(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
    {
        // The angle of the forward facing arrow sides against the x axis is
        // 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for
        // only half the strokewidth is processed ). Or 0.9862 for thin diamond.
        // Note these values and the tk variable below are dependent, update
        // both together (saves trig hard coding it).
        var swFactor = (type == mxConstants.ARROW_DIAMOND) ?  0.7071 : 0.9862;
        var endOffsetX = unitX * sw * swFactor;
        var endOffsetY = unitY * sw * swFactor;

        unitX = unitX * (size + sw);
        unitY = unitY * (size + sw);

        var pt = pe.clone();
        pt.x -= endOffsetX;
        pt.y -= endOffsetY;

        pe.x += -unitX - endOffsetX;
        pe.y += -unitY - endOffsetY;

        // thickness factor for diamond
        var tk = ((type == mxConstants.ARROW_DIAMOND) ?  2 : 3.4);

        return function()
        {
            canvas.begin();
            canvas.moveTo(pt.x, pt.y);
            canvas.lineTo(pt.x - unitX / 2 - unitY / tk, pt.y + unitX / tk - unitY / 2);
            canvas.lineTo(pt.x - unitX, pt.y - unitY);
            canvas.lineTo(pt.x - unitX / 2 + unitY / tk, pt.y - unitY / 2 - unitX / tk);
            canvas.close();

            if (filled)
            {
                canvas.fillAndStroke();
            }
            else
            {
                canvas.stroke();
            }
        };
    };

    mxMarker.addMarker('diamond', diamond);
    mxMarker.addMarker('diamondThin', diamond);
})();
